package com.xiaotu.spider.monitor;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.xiaotu.common.exception.SpiderException;
import com.xiaotu.common.exception.SpiderExceptionCode;
import com.xiaotu.common.model.SpiderLogModel;
import com.xiaotu.common.util.Constants;
import com.xiaotu.common.util.GsonUtils;
import com.xiaotu.common.util.PropertiesUtil;
import com.xiaotu.common.util.ThreadPool;

import net.sf.json.JSONObject;
import us.codecraft.webmagic.monitor.SpiderStatusMXBean;

/**
 * @类名 SpiderMonitorThread
 * @日期 2017年2月27日
 * @作者 高海军
 * @功能 采集任务监控线程
 */
@Component("spiderMonitorThread")
@Scope("prototype")
public class SpiderMonitorThread implements Runnable
{
	
	private static final Logger LOGGER = LoggerFactory
			.getLogger(SpiderMonitorThread.class);
	
	private SpiderStatusMXBean statusMXBean;// 监控实体
	
	private SpiderLogModel taskLog;// 任务基本信息
	
	private static final long TASK_LOG_INTERVAL = 12;// 循环监控多好次记一遍日志
	
	public static final String STATUS_STOPPED = "Stopped";
	
	public static final String STATUS_RUNNING = "running";
	
	@Autowired
	private RestTemplate restTemplate;
	
	public void init(SpiderStatusMXBean statusMXBean, SpiderLogModel taskLog)
	{
		this.statusMXBean = statusMXBean;
		this.taskLog = taskLog;
	}
	
	public void refreshTaskLog(final SpiderLogModel moniLog)
	{
		
		try
		{
			final String url = PropertiesUtil
					.getProperty(Constants.SpiderConfigKey.MONITOR_TASKLOG_URL);
			if (StringUtils.isEmpty(url))
				return;
			
			if (STATUS_STOPPED.equals(moniLog.getSpiderStatus()))
				moniLog.setEndTime(System.currentTimeMillis());
			
			String resp = restTemplate.postForObject(url,
					GsonUtils.toJson(moniLog), String.class);
			
			if (StringUtils.isEmpty(resp))
				throw new SpiderException(
						SpiderExceptionCode.MonitorLogRefreshExcepiton,
						"response is empty!");
			JSONObject res = JSONObject.fromObject(resp);
			if (res == null || res.isEmpty() || !res.has("status"))
				throw new SpiderException(
						SpiderExceptionCode.MonitorLogRefreshExcepiton,
						"response is empty!");
			String status = res.getString("status");
			if (!"0".equals(status))
				throw new SpiderException(
						SpiderExceptionCode.MonitorLogRefreshExcepiton,
						"status is " + status + "!");
		}
		catch (Exception e)
		{
			LOGGER.error("[{}] monitor refresh task log error!",
					moniLog.getJobType(), e);
		}
		
	}
	
	@Override
	public void run()
	{
		boolean isRunning = true;
		long times = 0;// 循环次数
		while (true)
		{
			try
			{
				SpiderLogModel moniLog = new SpiderLogModel();
				BeanUtils.copyProperties(moniLog, taskLog);
				
				moniLog.setRunningTime(
						System.currentTimeMillis() - taskLog.getStartTime());
				moniLog.setSpiderStatus(statusMXBean.getStatus());
				moniLog.setFinishedTarget(statusMXBean.getSuccessPageCount());
				moniLog.setLeftTarget(statusMXBean.getLeftPageCount());
				moniLog.setErrorTarget(statusMXBean.getErrorPageCount());
				moniLog.setTargetTotal(statusMXBean.getTotalPageCount());
				moniLog.setSecondsPerPage(statusMXBean.getPagePerSecond());
				moniLog.setStartTime(taskLog.getStartTime());
				moniLog.setTimestamp(System.currentTimeMillis());
				
				LOGGER.debug("[{}] monitor[{}]:{}", moniLog.getJobType(),
						statusMXBean.getName(), GsonUtils.toJson(moniLog));
				
				if (STATUS_STOPPED.equals(moniLog.getSpiderStatus()))
				{
					refreshTaskLog(moniLog);
					shutdownThreadPool();
					
					LOGGER.debug("monitor[{}]:Spider is stopped",
							statusMXBean.getName());
					isRunning = false;
					LOGGER.debug("[{}] Spider Task Finished! [{}]",
							taskLog.getJobType(), taskLog.getSeriesNo());
					
					return;
				}
				
				if (times % TASK_LOG_INTERVAL == 0)
					refreshTaskLog(moniLog);
			}
			catch (Exception e)
			{
				LOGGER.error("[{}] monitor[{}] error", taskLog.getJobType(),
						statusMXBean.getName(), e);
			}
			finally
			{
				try
				{
					times++;
					if (isRunning)
						Thread.sleep(Integer
								.parseInt(PropertiesUtil.getProperty(
										Constants.SpiderConfigKey.MONITOR_INTERVAL))
								* 1000);
				}
				catch (InterruptedException e)
				{
					LOGGER.error("[{}] monitor[{}] error", taskLog.getJobType(),
							statusMXBean.getName(), e);
				}
			}
		}
	}
	
	private void shutdownThreadPool()
	{
		LOGGER.debug("[{}] monitor log:jobNature:{}", taskLog.getJobType(),
				taskLog.getJobNature());
		if (Constants.LogConstants.TASK_NATURE_HANDLE != taskLog.getJobNature())
		{
			ThreadPool.shutdown();
			LOGGER.debug("[{}] monitor log:ThreadPool shutdown !",
					taskLog.getJobType());
		}
	}
}
